package gmu.swe.project.peer;

import static java.util.concurrent.TimeUnit.SECONDS;
import gmu.swe.project.io.DirectoryReader;
import gmu.swe.project.registry.TrackerRegistration;
import gmu.swe.project.tracker.TrackerInfo;
import gmu.swe.project.utils.Helper;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
 * A scheduled keep alive ping thread that will register the tracker the first
 * time and send subsequent keep alive pings to the registries at a scheduled
 * interval
 * 
 * 
 * @author Stacy Meyer
 * 
 */
public class PeerKeepAlivePingThread extends Thread {

	int interval = 0;
	final static ScheduledExecutorService scheduler = Executors
			.newScheduledThreadPool(1);
	private static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
	static SimpleDateFormat dfm = new SimpleDateFormat(DATE_FORMAT_NOW);
	private TrackerInfo tracker = null;

	PeerKeepAlivePingThread(int intervalArg, TrackerInfo tr) {
		super("PeerKeepAlivePingThread");
		this.interval = intervalArg;
		tracker = tr;
	}// PeerKeepAlivePingThread

	public void run() {

		System.out
				.println("PeerKeepAlivePingThread::KeepAlivePing thread spawned");

		try {
			pingRegistry();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}// run

	/**
	 * @throws Exception
	 * 
	 */
	private void pingRegistry() throws Exception {
		try {

			final Runnable keepAlivePing = new Runnable() {

				public void run() {

					Date time = Helper.getCurrTime();
					System.out
							.println("PeerKeepAlivePingThread()::Current time: "
									+ dfm.format(time));
					System.out
							.println("PeerKeepAlivePingThread::Ping Registry (every "
									+ Integer.toString(interval) + " seconds)");
					try {

						String ip = tracker.getIpAddress();
						Integer port = tracker.getListeningPort();

						Socket socketConnection = new Socket(ip, port);
						System.out
								.println("PeerKeepAlivePingThread::ip: " + ip);
						System.out.println("PeerKeepAlivePingThread::port: "
								+ port);
						// output stream to write to the server
						ObjectOutputStream clientOutputStream = new ObjectOutputStream(
								socketConnection.getOutputStream());

						// incoming stream to receive from the server
						ObjectInputStream clientInputStream = new ObjectInputStream(
								socketConnection.getInputStream());

						DirectoryReader reader = new DirectoryReader(
								PeerGUI.sharedDirectory);
						if (reader.queryDirectory())
							PeerGUI.info.setFiles(reader.getFilesInDirectory());

						clientOutputStream.writeObject(PeerGUI.info);

						// close the streams
						clientOutputStream.close();
						clientInputStream.close();
						socketConnection.close();

						// System.out
						// .println("PeerKeepAlivePingThread()::Client closed");
					} catch (Exception ex) {
						System.out
								.println("PeerKeepAlivePingThread::Exception thrown: "
										+ ex.toString());
						try {
							// go get a new tracker from the registries
							findNewTracker();
						} catch (Exception e) {
							// TODO Auto-generated catch block
							System.out
									.println("PeerKeepAlivePingThread::exception finding a new tracker");
							e.printStackTrace();
						}
					}// catch

					System.out
							.println("PeerKeepAlivePingThread::Done sending keep alive message");
				}// run
			};
			scheduler.scheduleAtFixedRate(keepAlivePing, 1, interval, SECONDS);

		} catch (Exception ex) {
			System.out
					.println("PeerKeepAlivePingThread()::Cannot connect, get another Tracker from "
							+ "the registry: " + ex.toString());
			findNewTracker();

		}
	}// pingRegistry

	private void findNewTracker() throws Exception {
		TrackerRegistration tr = PeerGUI.getTrackerRegistration();
		if (tr == null) {
			throw new Exception("All Registries are down!");
		}
		tracker = PeerGUI.getLeastWorkloadTracker(tr);
		PeerGUI.leastWorkloadTrackerInfo = tracker;
	}

}// class PeerKeepAlivePingThread(...
